import {Client, IMessage, messageCallbackType, StompHeaders} from "@stomp/stompjs";
import {StompSubscription} from "@stomp/stompjs/src/stomp-subscription";
import {StompConfig} from "@stomp/stompjs/src/stomp-config";
import {IFrame} from "@stomp/stompjs/src/i-frame";
import {loadEnv} from "@/utils/env";

/**
 * const stompConfig = {
      // 连接头信息，通常是认证登录信息
      connectHeaders: {
        login: "guest",
      },
      // 连接url，应该以 ws:// or wss:// 开头
      brokerURL: "ws://localhost:15674/ws",
      // debug
      debug: function (str: string) {
        console.log('STOMP: ' + str);
      },

      // 失败重连时间，200毫秒
      reconnectDelay: 200,

      // Subscriptions should be done inside onConnect as those need to reinstated when the broker reconnects
      // 连接成功的监听，订阅应该在他内部完成
      onConnect: function (frame) {
        // The return object has a method called `unsubscribe`
        // 订阅/topic/chat这个即可，返回的对象有一个unsubscribe的方法

      }
    }
 */
export class Stomp {
  stompClient!: Client;
  subscriptionMap: Map<string, StompSubscription | any> = new Map<string, StompSubscription | any>();
  isConnected: boolean = false

  constructor(stompConfig: StompConfig) {
    this.initStomp(stompConfig);
    this.activate()
  }

  private initStomp(stompConfig: StompConfig) {

    stompConfig.onConnect = this.onConnect.bind(this)
    stompConfig.reconnectDelay = 20000
    // 创建实例
    this.stompClient = new Client(stompConfig);
    // 发生错误的监听
    this.stompClient.onStompError = function (frame) {
      console.info('Broker reported error:' + frame.headers['message']);
      console.info('Additional details:' + frame.body);
    }

    // this.enableDebug()

  }

  forceDisconnect() {
    this.stompClient.forceDisconnect()
  }

  // 开启连接
  activate() {
    this.stompClient.activate()
  }

  // 关闭连接
  deactivate() {
    this.stompClient.deactivate()
  }

  enableDebug() {
    this.stompClient.debug = (data) => {
      console.log(data)
    }
  }

  disableDebug() {
    this.stompClient.debug = () => {
    }
  }

  protected onConnect(frame: IFrame) {
    this.isConnected = true
    let keys = this.subscriptionMap.keys();
    for (let key of keys) {
      let value = this.subscriptionMap.get(key);
      if (!(value instanceof StompSubscription)) {
        this.subscribe(key, value);
      }
    }
  }

  /**
   * const subscription = this.stompClient.subscribe('/topic/chat', function (message) {
      const payload = JSON.parse(message.body);
      // 接收到订阅的消息
    });
   * @param topic 订阅的主题
   * @param callback
   */
  subscribe(topic: string, callback: (message: object) => void) {
    if (this.isConnected) {
      const subscription = this.stompClient.subscribe(topic, (message => {
        try {
          callback(JSON.parse(message.body))
        } catch (e) {
          console.error(e)
        }
      }));
      this.subscriptionMap.set(topic, subscription);
    } else {
      this.subscriptionMap.set(topic, callback);
    }
  }

  /**
   * 取消阅主题
   * @param topic
   * @param header
   */
  unsubscribe(topic: string, header?: StompHeaders) {
    let subscription = this.subscriptionMap.get(topic);
    if (subscription) {
      try {
        subscription.unsubscribe(header);
      } catch (e) {
        console.error(e)
      }
      this.subscriptionMap.delete(topic);
    }
  }

  //const payLoad = {user: user, message: message};
  //     // 向服务端/topic/chat 发送数据，body只支持字符串，所以对象数据需转成字符串发送
  //     // 当然也可以通过headers发送，支持对象形式
  //     this.stompClient.publish({destination: '/topic/chat', body: JSON.stringify(payLoad)});
  //     // stompClient.publish({destination: '/topic/chat', headers: payLoad});
  publish(topic: string, payload?: object, headers?: StompHeaders) {
    let params = {destination: topic};
    if (payload) {
      // @ts-ignore
      params.body = JSON.stringify(payload);
    }
    if (headers) {
      // @ts-ignore
      params.headers = headers
    }
    this.stompClient?.publish(params);
  }

}

const {VITE_WEBSOCKET_URL} = loadEnv();
const stomp = new Stomp({brokerURL: VITE_WEBSOCKET_URL})

export default stomp
